package com.walle.ak47.commons.redis;

import java.util.List;

import org.apache.log4j.Logger;

import redis.clients.jedis.BinaryClient;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.exceptions.JedisException;

public class RedisList {

	public static Logger logger = Logger.getLogger(RedisList.class);
	
    JedisPool pool;
    String key;

    public RedisList(JedisPool pool, String name) {
        this.pool = pool;
        this.key = name;
    }

    public void release(Jedis jedis, boolean isBroken) {
		if (jedis != null) {
			if (isBroken) {
				pool.returnBrokenResource(jedis);
			} else {
				pool.returnResource(jedis);
			}
		}
	}
    
    /**
     * 获取列表长度
     *
     * @return 列表长度
     */
    public long size() {

    	long result = 0 ;
    	
    	boolean isBroken = false;
		Jedis jedis = null;
		try
		{
			jedis = pool.getResource() ;
			result = jedis.llen( this.key) ;
		}catch (JedisException e) {
			isBroken = true;
			logger.warn("failed:size(" + key + ")", e);
			throw e;
		} finally {
			release(jedis, isBroken);
		}
		return result;
    }

    /**
     * 获取指定位置的元素
     *
     * @param index 位置，负数表示从右边算起
     *
     * @return 元素，index 超出范围则返回 null
     */
    public String get( int index) {
    	
    	String result ;
    	
    	boolean isBroken = false;
		Jedis jedis = null;
		try
		{
			jedis = pool.getResource() ;
			result = jedis.lindex(RedisList.this.key, index) ;
		}catch (JedisException e) {
			isBroken = true;
			logger.warn("failed:get(" + key + ")", e);
			throw e;
		} finally {
			release(jedis, isBroken);
		}
		return result;
    	
    }

    /**
     * 在指定位置插入元素
     *
     * @param index 位置，负数表示从右边算起
     * @param value 元素
     */
    public void insert( int index, final String value) {
    	
    	boolean isBroken = false;
		Jedis jedis = null;
		try
		{
			jedis = pool.getResource() ;
			jedis.lset(key, index, value);
		}catch (JedisException e) {
			isBroken = true;
			logger.warn("failed:insert(" + key + ")", e);
			throw e;
		} finally {
			release(jedis, isBroken);
		}
    }

    /**
     * 在列表右边添加元素
     *
     * @param values           要添加的元素
     */
    public void add( String... values) {
    	
    	boolean isBroken = false;
		Jedis jedis = null;
		try
		{
			jedis = pool.getResource() ;
			jedis.rpush(key, values);
		}catch (JedisException e) {
			isBroken = true;
			logger.warn("failed:add(" + key + "),values("+ values.toString() +")", e);
			throw e;
		} finally {
			release(jedis, isBroken);
		}
		
    }

    /**
     * 在列表左边添加元素
     *
     * @param values           要添加的元素。注意添加顺序是按照参数顺序来，所以第一个参数第一个加入，当完成后，最后一个参数在最左边。
     */
    
    public void revAdd( String... values) {
    	
    	boolean isBroken = false;
		Jedis jedis = null;
		try
		{
			jedis = pool.getResource() ;
			jedis.lpush(key, values);
		}catch (JedisException e) {
			isBroken = true;
			logger.warn("failed:append(" + key + "),values("+ values.toString() +")", e);
			throw e;
		} finally {
			release(jedis, isBroken);
		}
		
    }

    /**
     * 在指定元素的左边添加元素
     *
     * @param pivot 目标元素的值
     * @param value 要插入的元素
     */
    public void insertBefore( String pivot, String value) {
    	
    	boolean isBroken = false;
		Jedis jedis = null;
		try
		{
			jedis = pool.getResource() ;
			jedis.linsert(key, BinaryClient.LIST_POSITION.BEFORE, pivot, value);
		}catch (JedisException e) {
			isBroken = true;
			logger.warn("failed:insertBefore(" + key + "),values("+ value.toString() +")", e);
			throw e;
		} finally {
			release(jedis, isBroken);
		}
		
    }

    /**
     * 在指定元素的右边添加元素
     *
     * @param pivot 目标元素的值
     * @param value 要插入的元素
     */
    public void insertAfter( String pivot, String value) {
    	
    	boolean isBroken = false;
		Jedis jedis = null;
		try
		{
			jedis = pool.getResource() ;
			jedis.linsert(key, BinaryClient.LIST_POSITION.AFTER, pivot, value);
		}catch (JedisException e) {
			isBroken = true;
			logger.warn("failed:insertAfter(" + key + "),pivot="+pivot+",values="+ value, e);
			throw e;
		} finally {
			release(jedis, isBroken);
		}
    	
    }

    /**
     * 从列表中删除 count 个 value 值
     *
     * @param value 要删除的元素
     * @param count 如果存在多个相同的元素，则指定删除多少个。0表示删除所有，1表示从左边起删除1个，-1表示从右边起删除1个，依此类推。
     *
     * @return 实际被删除的元素个数
     */
    public int remove( String value,  int count) {
    	
    	int result = -1 ;
    	
    	boolean isBroken = false;
		Jedis jedis = null;
		try
		{
			jedis = pool.getResource() ;
			result = jedis.lrem(key, count, value).intValue();
		}catch (JedisException e) {
			isBroken = true;
			logger.warn("failed:remove(" + key + "),count="+ count , e);
			throw e;
		} finally {
			release(jedis, isBroken);
		}
		
		return result ;
    }

    public int remove( String value )
    {

    	int result = -1 ;
    	
    	boolean isBroken = false;
		Jedis jedis = null;
		try
		{
			jedis = pool.getResource() ;
			result = jedis.lrem(key, 1, value).intValue();
		}catch (JedisException e) {
			isBroken = true;
			logger.warn("failed:remove(" + key + "),count=1" , e);
			throw e;
		} finally {
			release(jedis, isBroken);
		}
		
		return result ;
    }
    
    /**
     * 删除列表中除指定范围外的其他所有元素
     *
     * @param beginIndex 指定范围开始位置（含）
     * @param endIndex   指定范围结束位置（含）
     */
    public void trim( int beginIndex, int endIndex) {
    	
    	boolean isBroken = false;
		Jedis jedis = null;
		try
		{
			jedis = pool.getResource() ;
			jedis.ltrim(key, beginIndex, endIndex);
		}catch (JedisException e) {
			isBroken = true;
			logger.warn("failed:remove(" + key + "),count=1" , e);
			throw e;
		} finally {
			release(jedis, isBroken);
		}
		
    }

    /**
     * 返回子列表。sublist(0, -1) 表示返回所有的值
     *
     * @param beginIndex 开始位置（含）
     * @param endIndex   结束位置（含）
     *
     * @return 子列表
     */
    public List<String> sublist( int beginIndex, int endIndex) {
    	
    	List<String> result = null ;
    	
    	boolean isBroken = false;
		Jedis jedis = null;
		try
		{
			jedis = pool.getResource() ;
			result = jedis.lrange(key, beginIndex, endIndex);
		}catch (JedisException e) {
			isBroken = true;
			logger.warn("failed:remove(" + key + "),count=1" , e);
			throw e;
		} finally {
			release(jedis, isBroken);
		}
    	
    	return result ;
    }
     
}
